﻿using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Text;

namespace TSites.Utility
{
	public class eMailSender : LoggerBase
	{
		public event SendCompletedEventHandler EmailSendCompleted;

		#region Fields - eMail's server information

		private string SMTP_Server;
		private int SMTP_Port;
		private string UserID;
		private string Password;
		private string Alias;

		private bool ENABLE_SSL = false;
		private bool SEND_ASYNCHRONOUS = false;
		
		#endregion

		#region Constructor
		
		public eMailSender(string smtpServer, int smtpPort, string uid, string pwd, string alias,
			bool enableSSL, bool enableAsynSending)
		{
			SMTP_Server = smtpServer;
			SMTP_Port = smtpPort;
			UserID = uid;
			Password = pwd;
			Alias = alias;

			ENABLE_SSL = enableSSL;
			SEND_ASYNCHRONOUS = enableAsynSending;
		}

		#endregion

		/*
		 * Writing email to the IIS Server's SMTP service pickup directory is 
		 * another new feature of System.Net.Mail. 
		 * The SMTP pickup directory is a special directory used by Microsoft's SMTP service to send email. 
		 * Any email files found in that directory are processed and delivered over SMTP. 
		 * If the delivery process fails, the files are stored in a queue directory for delivery at another time. 
		 * If a fatal error occurs (such as a DNS resolution error), 
		 * the files are moved to the Badmail directory.
		 * By writing to the pickup directory, this speeds up the process because the entire chatting SMTP 
		 * layer used for relaying is by passed. 
		 * Below is an example of how to write directly to the Pickup directory.
		 * */
		public static bool PICKUP_DIRECTORY = false;

		public void SendWebPageAsMail(string mailTo, string[] Cc, string[] Bcc,
			string subject, string webPageURL)
		{
			WebRequest objRequest = System.Net.HttpWebRequest.Create(webPageURL);
            StreamReader sr = new StreamReader(objRequest.GetResponse().GetResponseStream());
			string body = sr.ReadToEnd();
            sr.Close();

			this.SendMail(mailTo, Cc, Bcc, subject, body, null, true);
		}

		public void SendMail(string mailTo, string[] Cc, string[] Bcc, string subject,
			string body, string fileAttachmentPath, bool isHtmlMail)
		{
			MailMessage mailMsg = null;
			SmtpClient client = null;
			try
			{
				mailMsg = new MailMessage(new MailAddress(UserID, Alias, Encoding.UTF8), 
					new MailAddress(mailTo));
				// CC
				if (Cc != null)
				{
					foreach (string item in Cc)
					{
						mailMsg.CC.Add(new MailAddress(item));
					}
				}
			
				// BCC
				if (Bcc != null)
				{
					foreach (string item in Cc)
					{
						mailMsg.Bcc.Add(new MailAddress(item));
					}
				}

				// Message			
				mailMsg.Subject = subject;
				mailMsg.Body = body;
				mailMsg.BodyEncoding = Encoding.UTF8;
				mailMsg.Priority = MailPriority.Normal;
			
				/*
				// attachment
				if (!String.IsNullOrEmpty(fileAttachmentPath))
				{
					mailMsg.Attachments.Add(new Attachment(fileAttachmentPath));
				}
				*/

				client = new SmtpClient(SMTP_Server, SMTP_Port);
				client.Credentials = new NetworkCredential(UserID, Password);
				//client.UseDefaultCredentials = false;
				client.EnableSsl = ENABLE_SSL;
			
				if (PICKUP_DIRECTORY)
					client.DeliveryMethod = SmtpDeliveryMethod.PickupDirectoryFromIis;

				if (!SEND_ASYNCHRONOUS)
				{
					try
					{
						client.Send(mailMsg);
					}
					catch (Exception ex)
					{
						// Error
						Error(ex.Message, ex);

						// Log content of email
						Info(LogErrorMail(mailMsg));
					}
				}
				else
				{
					// The userstate can be any object. The object can be accessed in the callback method
					// We should use our mailMsg for futher process!
					object userState = mailMsg;
					client.SendCompleted += new SendCompletedEventHandler(Client_SendCompleted);				
					client.SendAsync(mailMsg, userState);
				}
			}
			catch (Exception ex)
			{
				// Error
				Error(ex.Message, ex);
			}
		}

		/// <summary>
		/// Event handler when using asynchronus send mail method
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Client_SendCompleted(object sender, AsyncCompletedEventArgs e)
		{
			// Get the Original MailMessage object
			MailMessage mailMsg = (MailMessage)e.UserState;
            if (e.Error != null)
            {
				Info(LogErrorMail(mailMsg));
            }

			if (EmailSendCompleted != null)
			{
				EmailSendCompleted(sender, e);
			}
		}

		private string LogErrorMail(MailMessage mailMsg)
		{
			MailAddressCollection mailTo = mailMsg.To;
			string log = "To = {0}; CC = {1}; BCC = {2}; Subject = {3}; Body = {4}";
			return string.Format(log, (mailTo != null && mailTo.Count > 0) ? mailTo[0].Address : string.Empty,
				BuildCC(mailMsg.CC), BuildCC(mailMsg.Bcc), mailMsg.Subject, mailMsg.Body);
		}

		private string BuildCC(MailAddressCollection mailAddress)
		{
			StringBuilder builder = new StringBuilder(256);
			int count;
			if (mailAddress != null && (count = mailAddress.Count) > 0)
			{
				for (int i = 0; i < count - 1; i++)
				{
					builder.Append(mailAddress[i].Address).Append(", ");
				}
				builder.Append(mailAddress[count - 1].Address);
			}
			return builder.ToString();
		}

		protected override Type LogPrefix
		{
			get { return this.GetType(); }
		}
	}
}
